package com.googlecode.springgameengine.resource;

import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *
 * @author Maciej
 */
public class CachedResourceLoader<RD extends ResourceDescriptor> implements ResourceLoader<RD> {

	private Map<RD, Reference<Resource>> resourceCache = new HashMap<>();
	private List<RD> missingResources = new ArrayList<>();
	private ResourceLoader<? super RD> innerResourceLoader;

	@Override
	public <R extends Resource> R load(RD resourceDescriptor) throws ResourceNotLoadableException {
		//if resource exists in cache, return it
		Reference<Resource> resourceReference = resourceCache.get(resourceDescriptor);
		if (resourceReference != null) {
			Resource resource = resourceReference.get();
			if (resource != null) {
				return (R)resource;
			}
		}
		
		//else check if it is known to be missing to avoid perpetual missing resource loading
		if (missingResources.contains(resourceDescriptor)) {
			throw new MissingResourceException(resourceDescriptor);
		}
		//then load the resource and put it in cache
		try {
			R resource = innerResourceLoader.load(resourceDescriptor);
			resourceCache.put(resourceDescriptor, new SoftReference(resource));
			return resource;
		} catch (ResourceNotLoadableException ex) {
			//mark resourceDescriptor as missing to avoid perpetual missing resource loading
			missingResources.add(resourceDescriptor);
			throw ex;
		}
	}
	
	public void invalidate(RD resourceDescriptor) {
		resourceCache.remove(resourceDescriptor);
		missingResources.remove(resourceDescriptor);
	}
	
	public void invalidateAll() {
		resourceCache = new HashMap<>();
		missingResources = new ArrayList<>();
	}

	public ResourceLoader<? super RD> getInnerResourceLoader() {
		return innerResourceLoader;
	}

	public void setInnerResourceLoader(ResourceLoader<? super RD> innerResourceLoader) {
		this.innerResourceLoader = innerResourceLoader;
	}
}
